package com.yaolonga.itfc.manager.linux;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.yaolonga.itfc.manager.core.*;
import com.yaolonga.itfc.manager.core.exception.CmdExecuteException;
import com.yaolonga.itfc.manager.core.utils.CommandUtils;
import com.yaolonga.itfc.manager.core.utils.NetUtil;
import com.yaolonga.itfc.manager.core.wifi.*;
import com.yaolonga.itfc.manager.linux.netplan.NetplanConfig;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @Author: yaolong
 * @CreateTime: 2024-10-17  10:23
 * @Description: Ubuntu(linux)网卡信息提供者
 * @Version: 1.0
 */
@Slf4j
@Deprecated
public class UbuntuNetworkInterfaceManager extends AbstractNetworkInterfaceManager {

    private NetplanConfig netplanConfig;

    private final static String WIFI_LINK_CONF_PATH = "/etc/netplan/99-yl-net-init.yaml";
    private final static String fileName = "99-yl-net-init.yaml";


    public UbuntuNetworkInterfaceManager() {
        loadNetplanConfig();
    }


    private void loadNetplanConfig() {
        try {
            String ymlString = getNetplanConfig().toYmlString();
            String res = CommandUtils.execClassPathShFileAndReturn("init.sh", fileName, this.getClass().getClassLoader());
            if (res.trim().equals("-1")) {
                log.error("当前操作系统不支持netplan管理网络，请在系统中下载netplan");
                return;
            }
            log.info("已将/etc/netplan 下的yaml配置文件备份到 /etc/netplan/temp目录下，并将所有配置合并为单个配置文件99-yl-net-init.yaml");
            log.info("，若想恢复，删除99-yl-net-init.yaml；拷贝/etc/netplan/temp下配置文件到/etc/netplan");
            if (!res.isEmpty()) {
                createNewYamlFile(ymlString);
                log.info("create new netplan yaml file {} result: {}", WIFI_LINK_CONF_PATH, res);
            }
        } catch (Exception e) {
            log.error("load netplan config error", e);
        }
    }

    private NetplanConfig getNetplanConfig() {
        return NetplanConfig.createNetplanConfig(getNetplanConfigStream());
    }

    private InputStream getNetplanConfigStream() {
        return execCmd(Arrays.asList("netplan", "get")).getInputStream();
    }

    private String createNewYamlFile(String yml) {
        // chuangjian wenjian bing zuijia yaml dao wenjian zhong
        return execCmdAndReturn(Arrays.asList("sudo", "sh", "-c", "echo '" + yml + "' > " + WIFI_LINK_CONF_PATH));
    }

    // wifi相关
    @Override
    public PlatformType getPlatformType() {
        return PlatformType.linux;
    }

    @Override
    public SystemType getSystemType() {
        return SystemType.ubuntu;
    }

    /**
     * 获取网络配置输入流
     */
    protected InputStream getNetConfInputStream() {
        return getNetConfInputStream(null);
    }

    protected InputStream getNetConfInputStream(String interfaceName) {
        List<String> cmds = new ArrayList<>();
        cmds.add("nmcli");
        cmds.add("dev");
        cmds.add("show");
        if (interfaceName == null) {
            return execCmd(cmds).getInputStream();
        }
        cmds.add(interfaceName);
        return execCmd(cmds).getInputStream();
    }

    @Override
    public List<NetworkInterfaceInfo> getNetworkInterfaceInfos() {
        InputStream netConfInputStream = getNetConfInputStream();
        return doGetNetworkInterfaceInfos(netConfInputStream);
    }

    private List<NetworkInterfaceInfo> doGetNetworkInterfaceInfos(InputStream netConfInputStream) {

        // 获取永久路由
        this.netplanConfig = getNetplanConfig();
        Map<String, Map<String, Object>> netMap = getNetMap();
        List<NetworkInterfaceInfo> infos = new ArrayList<>();
        if (netConfInputStream != null) {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(netConfInputStream, getCharset()));
            String line;
            try {
                // 是否忽略行
                boolean ignoreLine = false;
                NetworkInterfaceInfo info = null;
                while ((line = bufferedReader.readLine()) != null) {
                    if (line.trim().isEmpty()) {
                        continue;
                    }
                    if (line.contains("GENERAL.DEVICE:")) {
                        info = new NetworkInterfaceInfo();
                        infos.add(info);
                        String[] split = line.split(": ");
                        if (split.length > 1) {
                            String value = split[1].trim();
                            Map<String, Object> metaInfo = netMap.get(value);
                            info.setId(value);
                            info.setDescription(value);
                            info.setName(value);
                            if (metaInfo != null) {
                                Object ifIndex = metaInfo.get("ifIndex");
                                info.setIfIndex((Integer) ifIndex);
                                Object dhcp = metaInfo.get("dhcp");
                                info.setDhcp((Boolean) dhcp);
                            }

                        }
                        continue;
                    }

                    if (line.contains("GENERAL.TYPE:")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String value = split[1].trim();
                            if (value.equalsIgnoreCase("wifi")) {
                                info.setType(InterfaceType.wifi);
                            } else if (value.equalsIgnoreCase("ethernet")) {
                                info.setType(InterfaceType.eth);
                            } else {
                                info.setType(InterfaceType.unknown);
                            }
                        }
                        continue;
                    }

                    if (line.contains("GENERAL.STATE:")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            boolean value = "100".equals(split[1]);
                            info.setState(value);
                        }
                        continue;
                    }

                    if (line.contains("GENERAL.MTU:")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String value = split[1].trim();
                            info.setMtu(Integer.parseInt(value));
                        }
                        continue;
                    }

                    if (line.contains("GENERAL.HWADDR:")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String value = split[1].trim();
                            info.setMac(value);
                        }
                        continue;
                    }

                    if (line.startsWith("IP4.ADDRESS")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String[] split1 = split[1].trim().split("/");
                            String value = split1[0];
                            if (split[0].contains("[1]")) {
                                info.addIp(NetworkAddress.of(value, true));
                            } else {
                                info.addIp(NetworkAddress.of(value, false));
                            }
                            int mask = Integer.parseInt(split1[1]);
                            info.setMask(NetUtil.getMaskIp(mask));
                        }
                        continue;
                    }
                    if (line.contains("IP4.GATEWAY:")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String value = split[1].trim();
                            if (!value.equals("--")) {
                                info.setGateway(value);
                            }

                        }
                        continue;
                    }

                    if (line.contains("IP4.DNS")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String value = split[1].trim();
                            System.out.println("interfaceDns：" + value);
                            if (split[0].contains("[1]")) {
                                info.addDns(NetworkAddress.of(value, true));
                            } else {
                                info.addDns(NetworkAddress.of(value, false));
                            }
                        }
                        continue;
                    }

                    if (line.contains("IP4.ROUTE")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String value = split[1].trim();
                            String[] split1 = value.split(",");
                            String s = split1[0].trim();
                            String[] split2 = s.split("=")[1].trim().split("/");
                            String target = split2[0].trim();
                            int mask = Integer.parseInt(split2[1].trim());
                            NetRoute netRoute = new NetRoute();
                            netRoute.setIfIndex(info.getIfIndex());


                            // 网络地址
                            netRoute.setTarget(target);
                            netRoute.setInterfaceName(info.getId());
                            netRoute.setMask(NetUtil.getMaskIp(mask));
                            if (!info.getIp().isEmpty()) {
                                netRoute.setIp(info.getIp().get(0).getIp());
                            }
                            // 网关
                            String s1 = split1[1].trim();
                            String[] split3 = s1.split("=");
                            String gateway = split3[1].trim();
                            if (!gateway.equals("--") && !gateway.equals("0.0.0.0")) {
                                // 如果网关为空则设置网关
                                if (null == info.getGateway()) {
                                    info.setGateway(gateway);
                                }
                            }
                            netRoute.setGateway(gateway);

                            // 跳数
                            String s2 = split1[2].trim();
                            String[] split4 = s2.split("=");
                            String metric = split4[1].trim();
                            netRoute.setMetric(metric);

                            // 设置路由类别
                            setRouteType(netRoute);
                            info.addRoute(netRoute);
                        }
                        continue;
                    }

                    if (line.contains("IP6.ADDRESS")) {
                        String[] split = line.split(": ");
                        if (split.length > 1 && info != null) {
                            String[] split1 = split[1].trim().split("/");
                            String value = split1[0];
                            int mask = Integer.parseInt(split1[1]);

                            if (split[0].contains("[1]")) {
                                info.addIpV6(NetworkAddress.of(value, true));
                            } else {
                                info.addIpV6(NetworkAddress.of(value, false));
                            }
                        }
                    }
                }
            } catch (IOException ignored) {
            }
        }


        return infos;
    }

    private void setRouteType(NetRoute netRoute) {
        JSONArray routes = this.netplanConfig.getRoutes(netRoute.getInterfaceName());
        if (routes != null) {
            // 如果路由存在则为永久路由
            if (routes.stream().anyMatch(jsonObject -> {
                String[] split = ((JSONObject) jsonObject).get("to", String.class).split("/");
                String target = split[0];
                String mask = "";
                if (split.length > 1) {
                    mask = NetUtil.getMaskIp(Integer.parseInt(split[1]));
                }
                String gateway = ((JSONObject) jsonObject).getStr("via", "--");
                String metric = ((JSONObject) jsonObject).getStr("metric", "--");
                return target.equals(netRoute.getTarget()) && mask.equals(netRoute.getMask()) && gateway.equals(netRoute.getGateway()) && netRoute.getMetric().equals(metric);
            })) {
                netRoute.setType(NetRouteType.PERMANENT_ROUTE);
            } else {
                // 如果路由不存在则为临时路由
                netRoute.setType(NetRouteType.TEMPORARY_ROUTE);
            }
        }
    }

    @Override
    public NetworkInterfaceInfo getNetworkInterfaceInfo(String interfaceName) {
        InputStream netConfInputStream = getNetConfInputStream(interfaceName);
        return doGetNetworkInterfaceInfos(netConfInputStream).stream().findFirst().orElse(null);
    }


    private Map<String, Map<String, Object>> getNetMap() {
        HashMap<String, Map<String, Object>> res = new HashMap<>();
        InputStream inputStream = execCmd("ip -o addr show").getInputStream();
        if (inputStream != null) {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, getCharset()));
            String line;
            try {
                // 是否忽略行
                boolean ignoreLine = false;
                while ((line = bufferedReader.readLine()) != null) {
                    // 忽略ipv6
                    if (line.contains("inet6")) {
                        continue;
                    }
                    String[] split = line.split(": ");
                    if (split.length > 1) {
                        int ifIndex = Integer.parseInt(split[0].trim());
                        String[] split1 = split[1].trim().split(" ");
                        String itfc = split1[0].trim();
                        boolean dhcp = false;
                        if (line.contains("global dynamic")) {
                            dhcp = true;
                        }
                        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
                        stringObjectHashMap.put("dhcp", dhcp);
                        stringObjectHashMap.put("ifIndex", ifIndex);
                        res.put(itfc, stringObjectHashMap);
                    }
                }
            } catch (IOException e) {

            }
        }

        return res;
    }


    /**
     * 配置应用指令
     *
     * @return 结果
     */
    private String netplanApply() {
        log.debug("执行 netplan apply");
        List<String> cmds = new ArrayList<>();
        cmds.add("netplan");
        cmds.add("apply");
        return execCmdAndReturn(cmds);
    }

    private List<String> getBaseConfSetCmds() {
        return getBaseConfSetCmds(true);
    }

    private List<String> getBaseConfSetCmds(boolean isCover) {
        List<String> cmds = new ArrayList<>();
        cmds.add("netplan");
        cmds.add("set");
        if (isCover) {
            cmds.add("--origin-hint");
        }
        cmds.add("99-yl-net-init");
        return cmds;
    }


    private String execConfSetCmd(Consumer<List<String>> call) {
        return execConfSetCmd(call, true);
    }

    private String execConfSetCmd(Consumer<List<String>> call, boolean isApply) {
        List<String> baseConfSetCmds = getBaseConfSetCmds();
        call.accept(baseConfSetCmds);
        String result = execCmdAndReturn(baseConfSetCmds);
        if (isApply) {
            String s = netplanApply();
            log.debug("配置结果 {}, apply res {}", result, s);
            return s;
        }
        System.out.println("exec cmds: >>" + baseConfSetCmds);
        return result;
    }


    @Override
    public String configDhcpIpAddress(String interfaceName) {
        if (interfaceName == null) {
            throw new IllegalArgumentException("interfaceName 不能为空");
        }
        return execConfSetCmd(cmds -> {
            cmds.add("ethernets." + interfaceName + "." + "dhcp4=true");
        });
    }

    @Override
    public String configDhcpDnsAddress(String interfaceName) {
        return "";
    }


    @Override
    public String configStaticIpAddress(String interfaceName, String ip, String mask, String gateway) {
        // ip
        List<String> ipCmd2 = getBaseConfSetCmds();
        ipCmd2.add("ethernets." + interfaceName + "." + "addresses=null");
        execCmdAndReturn(ipCmd2);

        List<String> ipCmd = getBaseConfSetCmds();
        ipCmd.add("ethernets." + interfaceName + "." + "addresses=[" + ip + "/" + NetUtil.getMaskNum(mask) + "]");
        execCmdAndReturn(ipCmd);

        // dhcp=false
        List<String> dhcpCmd = getBaseConfSetCmds();
        dhcpCmd.add("ethernets." + interfaceName + "." + "dhcp4=false");
        execCmdAndReturn(dhcpCmd);
        NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(interfaceName);

        if (networkInterfaceInfo != null) {
            // 清空之前的路由
            networkInterfaceInfo.getRoutes().forEach(route -> {
                if (route.isDefault()) {
                    // 删除路由
                    delRoute(route);
                }
            });
        }

        // gateway
        List<String> gatewayCmd = getBaseConfSetCmds();
        gatewayCmd.add("ethernets." + interfaceName + "." + "gateway4=" + gateway);
        execCmdAndReturn(gatewayCmd);
        return netplanApply();
    }


    @Override
    public String configStaticDnsAddress(String interfaceName, String dnsAddress) {
        return execConfSetCmd(cmds -> {
            // 判断当前地址是域名还是ip
            // 域名是字母，ip是数字
            JSONObject map = new JSONObject();
            if (dnsAddress.matches("^[a-zA-Z]+$")) {
                map.set("search", Collections.singletonList(dnsAddress));
            } else {
                map.set("addresses", Collections.singletonList(dnsAddress));
            }
            cmds.add("ethernets." + interfaceName + "." + "nameservers=" + map.toJSONString(0));
        });
    }

    @Override
    public String addDnsAddress(String interfaceName, String dnsAddress, int index) {
        List<String> cmds = new ArrayList<>();
        NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(interfaceName);
        if (networkInterfaceInfo != null) {
            List<NetworkAddress> dns = networkInterfaceInfo.getDns();
            if (dns.stream().anyMatch(i -> i.getIp().equals(dnsAddress))) {
                return "";
            }
            if (index == -1) {
                dns.add(NetworkAddress.of(dnsAddress, false));
            } else {
                dns.add(index, NetworkAddress.of(dnsAddress, false));
            }
            cmds.addAll(parseSetDnsConfCmds(interfaceName, dns));
        } else {
            // 判断当前地址是域名还是ip
            // 域名是字母，ip是数字
            JSONObject map = new JSONObject();
            if (dnsAddress.matches("^[a-zA-Z]+$")) {
                map.set("search", Collections.singletonList(dnsAddress));
            } else {
                map.set("addresses", Collections.singletonList(dnsAddress));
            }
            cmds.add("ethernets." + interfaceName + "." + "nameservers=" + map.toJSONString(0));
        }
        return execConfSetCmd((_cmd) -> _cmd.addAll(cmds));
    }

    /**
     * 解析dns配置set指令
     *
     * @param interfaceName
     * @param dns
     * @return
     */
    private List<String> parseSetDnsConfCmds(String interfaceName, List<NetworkAddress> dns) {
        List<String> cmds = new ArrayList<>();
        // domain \ ip
        List<String> domains = new ArrayList<>();
        List<String> ips = new ArrayList<>();
        for (NetworkAddress dn : dns) {
            if (dn.getIp().matches("^[a-zA-Z]+$")) {
                domains.add(dn.getIp());
            } else {
                ips.add(dn.getIp());
            }
        }
        JSONObject nameservers = new JSONObject();
        if (!domains.isEmpty()) {
            nameservers.set("search", domains);
        }
        if (!ips.isEmpty()) {
            nameservers.set("addresses", ips);
        }
        cmds.add("ethernets." + interfaceName + "." + "nameservers=" + nameservers.toJSONString(0));
        return cmds;
    }

    /**
     * 解析路由配置set指令
     *
     * @param interfaceName
     * @param routes
     * @return
     */
    private List<String> parseSetRouteConfCmds(String interfaceName, JSONArray routes) {
        List<String> cmds = new ArrayList<>();
        cmds.add("ethernets." + interfaceName + "." + "routes=" + routes.toJSONString(0));
        return cmds;
    }


    @Override
    public String addDnsAddress(String interfaceName, String dnsAddress) {
        return addDnsAddress(interfaceName, dnsAddress, -1);
    }


    @Override
    public String delDnsAddress(String interfaceName, String dnsAddress) {
        // 先删除所有的
        execConfSetCmd(cmds -> cmds.add("ethernets." + interfaceName + "." + "nameservers=null"), false);
        return execConfSetCmd(cmds -> {
            NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(interfaceName);
            if (networkInterfaceInfo != null) {
                List<NetworkAddress> dns = networkInterfaceInfo.getDns();
                dns.removeIf(i -> i.getIp().equals(dnsAddress));
                if (!dns.isEmpty()) {
                    cmds.addAll(parseSetDnsConfCmds(interfaceName, dns));
                }
            }
        });
    }

    @Override
    public String addRoute(NetRoute route) {
        route.validate();
        List<String> cmds;
        NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(route.getInterfaceName());

        if (networkInterfaceInfo != null) {
            List<NetRoute> routes = networkInterfaceInfo.getRoutes();
            if (routes.stream().noneMatch(i ->
                    i.getTarget().equals(route.getTarget()) &&
                            i.getMask().equals(route.getMask()) &&
                            i.getGateway().equals(route.getGateway()) &&
                            i.getType().equals(route.getType()))
            ) {
                // 添加永久路由
                if (route.getType().equals(NetRouteType.PERMANENT_ROUTE)) {
                    cmds = getBaseConfSetCmds();
                    JSONArray routes1 = this.netplanConfig.getRoutes(route.getInterfaceName());
                    HashMap<String, Object> _route = new HashMap<>();
                    _route.put("via", route.getGateway());
                    _route.put("to", route.getTargetAndMask());
                    if (null != route.getMetric()) {
                        _route.put("metric", route.getMetric());
                    }
                    routes1.add(_route);
                    List<String> routeCmds = parseSetRouteConfCmds(route.getInterfaceName(), routes1);
                    cmds.addAll(routeCmds);
                    execCmdAndReturn(cmds);
                    String s = netplanApply();
                    return s;
                } else {
//                    ip route add 192.168.0.0/24 via 192.168.137.1 metric 200
                    cmds = new ArrayList<>();
                    cmds.add("ip");
                    cmds.add("route");
                    cmds.add("add");
                    cmds.add(route.getTargetAndMask());
                    cmds.add("via");
                    cmds.add(route.getGateway());
                    if (route.getMetric() != null) {
                        cmds.add("metric");
                        cmds.add(route.getMetric());
                    }
                    // 临时路由
                    String s = execCmdAndReturn(cmds);
                    return s;

                }
            }

        }
        return "";
    }

    /**
     * CHANGE  只用于修改网关和/或跃点数。
     *
     * @param route 路由配置
     * @return 结果
     */
    @Override
    public String changeRoute(NetRoute route) {
        route.validate();
        NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(route.getInterfaceName());
        // 如果是临时路由直接修改，否则永久路由则修改netplan文件
        if (route.getType().equals(NetRouteType.TEMPORARY_ROUTE)) {
            List<String> cmds = new ArrayList<>();
            cmds.add("ip");
            cmds.add("route");
            cmds.add("change");
            cmds.add(route.getTargetAndMask());
            if (null != route.getGateway()) {
                cmds.add("via");
                cmds.add(route.getGateway());
            }
            if (null != route.getMetric()) {
                cmds.add("metric");
                cmds.add(route.getMetric());
            }
            cmds.add("dev");
            cmds.add(route.getInterfaceName());
            return execCmdAndReturn(cmds);
        } else {
            List<String> baseConfSetCmds = getBaseConfSetCmds();
            // 重新设置
            JSONArray routes = this.netplanConfig.getRoutes(route.getInterfaceName());
            if (Objects.nonNull(routes)) {
                // 先清空
                baseConfSetCmds.add("ethernets." + route.getInterfaceName() + "." + "routes=null");
                String result = execCmdAndReturn(baseConfSetCmds);
                String res = execConfSetCmd((cmds) -> {
                    routes.stream()
                            .filter(i -> {
                                String target = route.getTargetAndMask();
                                JSONObject entries = new JSONObject(i);
                                String s = entries.get("to", String.class);
                                return target.equals(s);
                            })
                            .forEach(i -> {
                                JSONObject jsonObject = (JSONObject) i;
                                jsonObject.set("via", route.getGateway());
                                jsonObject.set("metric", route.getMetric());
                            });
                    cmds.addAll(parseSetRouteConfCmds(route.getInterfaceName(), routes));
                });
                return result + " " + res;
            }
        }
        return "";
    }

    @Override
    public String delRoute(NetRoute route) {
        route.validate();
        NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(route.getInterfaceName());
        if (networkInterfaceInfo != null) {
            List<NetRoute> routes = networkInterfaceInfo.getRoutes();
            if (routes.stream().anyMatch(i ->
                    i.getTarget().equals(route.getTarget()) &&
                            i.getMask().equals(route.getMask()) &&
                            i.getGateway().equals(route.getGateway()) &&
                            i.getType().equals(route.getType()))
            ) {
                // 删除永久路由
                if (route.getType().equals(NetRouteType.PERMANENT_ROUTE)) {
                    return execConfSetCmd(cmds -> {
                        JSONArray routes1 = this.netplanConfig.getRoutes(route.getInterfaceName());
                        routes1.removeIf(i -> {
                            JSONObject jsonObject = (JSONObject) i;
                            String target = route.getTargetAndMask();
                            String s = jsonObject.get("to", String.class);
                            return target.equals(s);
                        });
                        execConfSetCmd(cmds1 -> cmds1.add("ethernets." + route.getInterfaceName() + "." + "routes=null"), false);
                        cmds.add("ethernets." + route.getInterfaceName() + "." + "routes=" + routes1.toJSONString(0));
                    });
                } else {
                    List<String> cmds = new ArrayList<>();
                    cmds.add("ip");
                    cmds.add("route");
                    cmds.add("del");
                    cmds.add(route.getTargetAndMask());
                    if (null != route.getGateway()) {
                        cmds.add("via");
                        cmds.add(route.getGateway());
                    }
                    cmds.add("dev");
                    cmds.add(route.getInterfaceName());
                    return execCmdAndReturn(cmds);
                }
            }
        }

        return "";
    }

    @Override
    public WifiScanInfo scanWifiInfo(String interfaceName) {
        Process process = execCmd("nmcli -m tabular -f all dev wifi list --rescan yes ifname " + interfaceName);
        InputStream inputStream = process.getInputStream();

//        ClassPathResource classPathResource = new ClassPathResource("WifiScanInfo.log", this.getClass().getClassLoader());
//        InputStream inputStream = classPathResource.getStream();

        WifiScanInfo wifiScanInfo = new WifiScanInfo();
        wifiScanInfo.setInterfaceName(interfaceName);
        if (null != inputStream) {
            Map<String, Map<String, Object>> ssidMap = WIfiScanHelper.parseWifiScanInfo(inputStream);
            List<SSIDInfo> ssidList = wifiScanInfo.getSsidList();
            Map<String, SSIDInfo> ssidsMap = new HashMap<>();
            // group by ssid
            for (Map<String, Object> value : ssidMap.values()) {
                BSSIDInfo bssidInfo = new BSSIDInfo();
                bssidInfo.setBssid(MapUtil.getStr(value, "BSSID", null));
                bssidInfo.setMode(MapUtil.getStr(value, "MODE", null));
                bssidInfo.setSsid(MapUtil.getStr(value, "SSID", null));
                bssidInfo.setChannel(MapUtil.getStr(value, "CHAN", null));
                bssidInfo.setRate(MapUtil.getStr(value, "RATE", null));
                bssidInfo.setSignal(MapUtil.getStr(value, "SIGNAL", null));
                String freq = MapUtil.getStr(value, "FREQ", null);
                String state = MapUtil.getStr(value, "ACTIVE", null);
                if (state.equals("yes")) {
                    bssidInfo.setState(ConState.connected);
                } else {
                    bssidInfo.setState(ConState.disconnect);
                }
                bssidInfo.setWaveBand(formatFreq(freq));
                SSIDInfo ssidInfo = ssidsMap.computeIfAbsent(bssidInfo.getSsid(), key -> new SSIDInfo());
                if (Objects.isNull(ssidInfo.getSsid())) {
                    ssidInfo.setSsid(bssidInfo.getSsid());
                    ssidInfo.setInterfaceName(interfaceName);
                    ssidInfo.setEncryption(MapUtil.getStr(value, "WPA-FLAGS", null));
                    ssidInfo.setNetworkType("--");
                    String security = MapUtil.getStr(value, "SECURITY", null);
                    ssidInfo.setSecureType(formatSecurityType(security));
                }
                ssidInfo.addBssid(bssidInfo);
            }
            ssidList.addAll(ssidsMap.values());
        }
        return wifiScanInfo;
    }

    private String formatFreq(String freq) {
        String[] split = freq.split("\\s+");
        if (split.length > 1) {
            if ("GHz".equals(split[1])) {
                return freq;
            } else if ("MHz".equals(split[1])) {
                BigDecimal bigDecimal = new BigDecimal(split[0]);
                String hz = bigDecimal.divide(new BigDecimal(1000)).setScale(1, BigDecimal.ROUND_DOWN).toString();
                return hz + " GHz";
            }
        }
        return freq;
    }

    private String formatSecurityType(String security) {
        if (security.equals("--")) {
            return WifiSecureType.OPEN.name();
        } else {
            String[] split1 = security.split(" ");
            if (split1.length > 1) {
                return split1[split1.length - 1];
            } else {
                return split1[0];
            }
        }
    }


    @Override
    public WifiLinkInfo getWifiLinkInfo(String interfaceName) {
        WifiLinkInfo wifiLinkInfo = new WifiLinkInfo();
        WifiScanInfo wifiScanInfo = scanWifiInfo(interfaceName);
        SSIDInfo ssidInfo = wifiScanInfo.getSsidList().stream().filter(ssid -> ssid.getState().equals(ConState.connected)).findFirst().orElse(null);
        if (Objects.nonNull(ssidInfo)) {

            BSSIDInfo bssidInfo = ssidInfo.getBssid().stream().filter(i -> i.getState().equals(ConState.connected)).findFirst().orElse(null);
            if (Objects.nonNull(bssidInfo)) {
                wifiLinkInfo.setState(ssidInfo.getState());
                wifiLinkInfo.setSsid(ssidInfo.getSsid());
                wifiLinkInfo.setChannel(bssidInfo.getChannel());
                wifiLinkInfo.setBssid(bssidInfo.getBssid());
                wifiLinkInfo.setMode(bssidInfo.getMode());
                wifiLinkInfo.setSignal(bssidInfo.getSignal());
                wifiLinkInfo.setEncryption(ssidInfo.getEncryption());
                wifiLinkInfo.setDescription(interfaceName);
                wifiLinkInfo.setConfigFile("Unknown");
                wifiLinkInfo.setSecureType(ssidInfo.getSecureType());
                wifiLinkInfo.setWaveBand(bssidInfo.getWaveBand());
                NetworkInterfaceInfo networkInterfaceInfo = getNetworkInterfaceInfo(interfaceName);
                String mac = networkInterfaceInfo.getMac();
                wifiLinkInfo.setMac(mac);
                return wifiLinkInfo;
            }
        }
        return null;
    }

    @Override
    public List<WifiLinkInfo> getWifiLinkInfos() {
        return getNetworkInterfaceInfos()
                .stream()
                .filter(i -> i.getType().equals(InterfaceType.wifi))
                .map(i -> getWifiLinkInfo(i.getId()))
                .collect(Collectors.toList());
    }

    @Override
    public WifiLinkConf getWifiConf(String interfaceName, String profileName) {
        return getWifiProfile(interfaceName, profileName);
    }

    private WifiLinkConf getWifiProfile(String interfaceName, String profileName) {
        String cmd = "nmcli connection show " + profileName + " -s | grep -E  \"seen-bssids:|channel:|wireless.ssid:|interface-name:|connection.id:|security.psk:|security.key-mgmt:|connection.uuid:\"";
        Process process = execCmd(cmd);
        InputStream inputStream = process.getInputStream();
        try {
//
//            ClassPathResource classPathResource = new ClassPathResource("wifiConf", this.getClass().getClassLoader());
//            InputStream inputStream = classPathResource.getStream();

            if (null != inputStream) {
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                String line;
                WifiLinkConf conf = new WifiLinkConf();
                List<WifiLinkConf> confs = new ArrayList<>();
                while ((line = bufferedReader.readLine()) != null) {
                    line = line.trim();
                    if (line.isEmpty()) {
                        continue;
                    }

                    String[] split = line.split(": ");
                    if (split.length > 1) {
                        String value = split[1].trim();
                        if (line.contains(".id:")) {
                            conf = new WifiLinkConf();
                            confs.add(conf);
                            conf.setName(value);
                            continue;
                        }
                        if (line.contains("wireless.ssid:")) {
                            conf.setSsid(value);
                            continue;
                        }
                        if (line.contains("interface-name:")) {
                            conf.setInterfaceName(value);
                            continue;
                        }
                        if (line.contains("security.psk:")) {
                            conf.setPassword(value);
                        }
                        if (line.contains("autoconnect:")) {
                            if ("yes".equals(value)) {
                                conf.setAutoConnection(true);
                            } else {
                                conf.setAutoConnection(false);
                            }
                        }

                        if (line.contains("connection.uuid:")) {
                            conf.setId(value);
                            continue;
                        }
                        if (line.contains("security.key-mgmt:")) {
                            if (value.equals("wpa-psk")) {
                                // TODO
                                conf.setSecureType(WifiSecureType.WPA2.name());
                            } else if (value.equals("none")) {
                                conf.setSecureType(WifiSecureType.OPEN.name());
                            }
                        }
                    }
                }
                return confs.stream().filter(i -> i.getInterfaceName().equals(interfaceName)).findFirst().orElse(null);
            }
            return null;
        } catch (Exception e) {
            log.error("get conf error", e);
            return null;
        }
    }


    @Override
    public String connectWifi(WifiLinkConf wifiLinkConf)  {
        try {

            String profileName = wifiLinkConf.getName();
            if (profileName == null || profileName.isEmpty()) {
                profileName = wifiLinkConf.getSsid();
                wifiLinkConf.setName(profileName);
            }

            if (wifiLinkConf.getSecureType() == null && wifiLinkConf.getPassword() == null) {
                wifiLinkConf.setSecureType(WifiSecureType.OPEN.name());
            }

            // 创建配置文件
            setWifiConf(wifiLinkConf);
            List<String> cmds = new ArrayList<>();
            cmds.add("nmcli");
            cmds.add("con");
            cmds.add("up");
            cmds.add(wifiLinkConf.getName());
            cmds.add("ifname");
            cmds.add(wifiLinkConf.getInterfaceName());
            String res = execCmdAndReturn(cmds);
            log.debug("连接wifi成功：{}", res);
            return res;
        } catch (Exception e) {
            log.error("连接wifi异常：{}", e.getMessage(), e);
            throw new CmdExecuteException("连接wifi异常：" + e.getMessage(), e);
        }
    }

    @Override
    public String disconnectWifi(String interfaceName) {
        List<String> cmds = new ArrayList<>();
        cmds.add("nmcli");
        cmds.add("d");
        cmds.add("disconnect");
        cmds.add(interfaceName);
        return execCmdAndReturn(cmds);
    }

    @Override
    public String forgetWifi(String interfaceName, String profileName) {
        String s1 = disconnectWifi(interfaceName);
        String s = delWifiConf(interfaceName, profileName);
        log.debug("忘记wifi成功： {}", s);
        return String.format("disconnect: %s \n del profile: %s", s1, s);
    }

    @Override
    public String setWifiConf(WifiLinkConf wifiLinkConf) {
        WifiLinkConf wifiProfile = getWifiProfile(wifiLinkConf.getInterfaceName(), wifiLinkConf.getName());
        if (Objects.isNull(wifiProfile)) {
            List<String> cmds = new ArrayList<>();
            cmds.add("nmcli");
            cmds.add("con");
            cmds.add("add");
            cmds.add("con-name");
            cmds.add(wifiLinkConf.getName());
            cmds.add("ifname");
            cmds.add(wifiLinkConf.getInterfaceName());
            cmds.add("autoconnect");
            if (wifiLinkConf.isAutoConnection()) {
                cmds.add("yes");
            } else {
                cmds.add("no");
            }
            cmds.add("type");
            cmds.add("wifi");
            cmds.add("ssid");
            cmds.add(wifiLinkConf.getSsid());
            if (!wifiLinkConf.getSecureType().equals(WifiSecureType.OPEN.name())) {
                cmds.add("wifi-sec.key-mgmt");
                cmds.add("wpa-psk");
                cmds.add("wifi-sec.psk");
                cmds.add(wifiLinkConf.getPassword());
            }

            String s = execCmdAndReturn(cmds);
            log.debug("create wifi profile: {}", s);
            return s;
        } else {
            List<String> cmds = new ArrayList<>();
            cmds.add("nmcli");
            cmds.add("con");
            cmds.add("mod");
            // auto con change
            if (wifiLinkConf.isAutoConnection() != (wifiProfile.isAutoConnection())) {
                cmds.add("autoconnect");
                cmds.add(wifiLinkConf.isAutoConnection() ? "yes" : "no");
            }
            // update
            if (!WifiSecureType.OPEN.name().equals(wifiLinkConf.getSecureType())) {
                // password change
                if (!wifiLinkConf.getPassword().equals(wifiProfile.getPassword())) {
                    cmds.add("wifi-sec.psk");
                    cmds.add(wifiLinkConf.getPassword());
                }
            } else {
                // set wifi-sec.key-mgmt none
                cmds.add("key-mgmt");
                cmds.add("none");
            }
            if (cmds.size() > 3) {
                String res = execCmdAndReturn(cmds);
                log.debug("update wifi profile: {}", res);
                return res;
            }
        }
        log.debug("set wifi profile: no change");
        return "";
    }

    @Override
    public String delWifiConf(String interfaceName, String profileName) {
        WifiLinkConf wifiProfile = getWifiProfile(interfaceName, profileName);
        if (Objects.isNull(wifiProfile)) {
            log.warn("删除wifi配置文件： does not exist");
            return "conf " + profileName + "does not exist";
        }
        List<String> cmds = new ArrayList<>();
        cmds.add("nmcli");
        cmds.add("con");
        cmds.add("delete");
        if (!Objects.isNull(wifiProfile.getId())) {
            cmds.add(wifiProfile.getId());
        } else {
            cmds.add(wifiProfile.getName());
        }
        String s = execCmdAndReturn(cmds);
        log.debug("删除wifi配置文件成功： {}", s);
        return s;
    }

    /**
     * 多wifi网卡会enabled所有的设备
     *
     * @param interfaceName 网卡名称
     * @return res
     */
    @Override
    public String enableWifi(String interfaceName) {
        List<String> cmds = new ArrayList<>();
        cmds.add("nmcli");
        cmds.add("radio");
        cmds.add("wifi");
        cmds.add("on");
        String res = execCmdAndReturn(cmds);
        log.debug("启用wifi {}", res);
        return res;
    }

    /**
     * 多wifi网卡会断开所有的设备
     *
     * @param interfaceName 网卡名称
     * @return res
     */
    @Override
    public String disableWifi(String interfaceName) {
        List<String> cmds = new ArrayList<>();
        cmds.add("nmcli");
        cmds.add("radio");
        cmds.add("wifi");
        cmds.add("off");
        String res = execCmdAndReturn(cmds);
        log.debug("禁用用wifi {}", res);
        return res;
    }


    public static void main(String[] args) throws IOException {

        UbuntuNetworkInterfaceManager ubuntuNetworkInterfaceManager = new UbuntuNetworkInterfaceManager();

//        ubuntuNetworkInterfaceManager.scanWifiInfo("");
//        ubuntuNetworkInterfaceManager.getWifiLinkInfo("");
//        ubuntuNetworkInterfaceManager.getWifiConf("", "");

//        NetplanConfig netplanConfig1 = ubuntuNetworkInterfaceManager.getNetplanConfig();
//        System.out.println(netplanConfig1);


//        List<NetworkInterfaceInfo> networkInterfaceInfos = ubuntuNetworkInterfaceManager.getNetworkInterfaceInfos();
//        System.out.println(networkInterfaceInfos);

//
//        NetRoute netRoute = new NetRoute();
//        netRoute.setTarget("10.1.0.0");
//        netRoute.setGateway("10.1.1.2");
//        netRoute.setMask("255.255.0.0");
//        netRoute.setMetric("1");
//        netRoute.setInterfaceName("ens33");
//        netRoute.setType(NetRouteType.PERMANENT_ROUTE);

//        ubuntuNetworkInterfaceManager.configDhcpIpAddress("ens33");
//        ubuntuNetworkInterfaceManager.configStaticIpAddress("ens33", "10.1.31.70", "255.255.0.0", "10.1.1.1");
//        ubuntuNetworkInterfaceManager.configStaticIpAddress("ens33", "192.168.0.106", "255.255.255.0", "192.168.0.1");
//        ubuntuNetworkInterfaceManager.configStaticDnsAddress("ens33","10.1.1.1");
//        ubuntuNetworkInterfaceManager.addDnsAddress("ens33","114.114.114.114",0);
//        ubuntuNetworkInterfaceManager.delDnsAddress("ens33", "114.114.114.114");

//        System.out.println(set);

//        ubuntuNetworkInterfaceManager.delRoute(netRoute);
//        ubuntuNetworkInterfaceManager.addRoute(netRoute);
//        ubuntuNetworkInterfaceManager.addRoute(netRoute);
//        ubuntuNetworkInterfaceManager.changeRoute(netRoute);
//        winEthNetworkInterfaceManager.configStaticIpAddress("WLAN", "192.168.1.101", "255.255.255.0", "192.168.1.1");
//
//        String s = winEthNetworkInterfaceManager.execCmdAndReturn("");
//        System.out.println(s);

//        winEthNetworkInterfaceManager.delRoute(
//                NetRoute.builder()
//                        .target("192.168.1.0")
//                        .gateway("192.168.1.1")
//                        .mask("255.255.255.0")
//                        .metric("1")
//                        .ifIndex(1)
//                        .build()
//        );

//        List<NetRoute> netIp4Routes = winEthNetworkInterfaceManager.getNetIp4Routes();


//        List<NetworkInterfaceInfo> networkInterfaceInfos = winEthNetworkInterfaceManager.getNetworkInterfaceInfos();
//        System.out.println(networkInterfaceInfos);


//        // 测试 扫描wifi信息指令
//        WifiScanInfo wifiScanInfo = winEthNetworkInterfaceManager.scanWifiInfo("WLAN");
//        System.out.println(wifiScanInfo);


//        // 测试 断开wifi连接
//        String s = winEthNetworkInterfaceManager.disconnectWifi("WLAN");
//        System.out.println(s);


//        // 获取wifi配置列表
//        WifiLinkConf wifiProfile = winEthNetworkInterfaceManager.getWifiProfile("WLAN", "MicroID");
//        System.out.println(wifiProfile);

//        // 获取wifi连接信息
//        List<WifiLinkInfo> wifiLinkInfos = winEthNetworkInterfaceManager.getWifiLinkInfos();
//        System.out.println(wifiLinkInfos);

//
//        // 测试删除wifi配置
//        String s1 = winEthNetworkInterfaceManager.delWifiConf("WLAN", "mi 13");
//        System.out.println("删除wifi：" + s1);
//
//

//        // 测试设置wifi配置
//        WifiLinkConf wifiLinkConf = new WifiLinkConf();
//        wifiLinkConf.setAutoConnection(true);
//        wifiLinkConf.setName("mi 13");
//        wifiLinkConf.setSsid("mi 13");
//        wifiLinkConf.setInterfaceName("WLAN");
//        wifiLinkConf.setSecureType(WifiSecureType.OPEN.name());
//        String s = winEthNetworkInterfaceManager.setWifiConf(wifiLinkConf);
//        System.out.println("设置wifi：" + s);
//

//        // 获取wifi配置
//        WifiLinkConf wifiProfile = winEthNetworkInterfaceManager.getWifiProfile("WLAN", "mi 13");
//        System.out.println("wifi配置：" + wifiProfile);

//        // 连接wifi
//        String s2 = winEthNetworkInterfaceManager.connectWifi(wifiLinkConf);
//        System.out.println("连接wifi：" + s2);


//        // 测试忘记连接
//        String s3 = winEthNetworkInterfaceManager.forgetWifi("WLAN","21-2-5-3");
//        System.out.println("忘记连接：" + s3);

//        // 测试断开连接
//        String s4 = winEthNetworkInterfaceManager.disconnectWifi("WLAN");
//        System.out.println("断开连接：" + s4);

//        // 测试禁用wlan
//        String s5 = winEthNetworkInterfaceManager.disableWifi("WLAN");
//        System.out.println("禁用wlan：" + s5);


//       // 测试启用wlan
//        String s6= winEthNetworkInterfaceManager.enableWifi("WLAN");
//        System.out.println("启用wlan：" + s6);
    }
}
